// Haxy helper
$Q = new Quaternion;

var avatar;

var fps = 40.0;

function FlyingSheep(){
  print("Registered the flying sheep controls");

  var avatar = world.getNodeById("/Viewer/Avatar"),
    speed = 5 * (1 / 40),
    climbSpeed = 5 * (1 / 40),
    turnSpeed = 90 * (1 / 40),
    velocity = new Vector(0,0,speed),
    direction = new Quaternion,
    roll = 0,
    pitch = 0,
    yaw = 0;
  
  this.frameListener = function(){
    var v = avatar.getPosition(),
      q = avatar.getRotation();

    if(oisinput.isKeyDown(Keycodes.KC_SPACE)){
      print("sent a message..");
//      connection.send("server@weheartplaces.com", "hello <zing zah>there</zing zah>!")
    }
    
    if(oisinput.isKeyDown(Keycodes.KC_LEFT)){
      roll -= 3;
    }
    
    if(oisinput.isKeyDown(Keycodes.KC_RIGHT)){
      roll += 3;
    }
    
    if(oisinput.isKeyDown(Keycodes.KC_DOWN)){
      pitch -= 1; // climbs slower
    }
    
    if(oisinput.isKeyDown(Keycodes.KC_UP)){
      pitch += 2;
    }

    // Sheep can only fly at '45 roll
    if(roll!=0){
      roll += (roll < 0) ? 0.5 : -0.5;
      roll = Math.clamp(roll, -45, 45);

      // The yaw comes from the roll (go go lollerphysics!)
      yaw -= roll / 30;
    }
    
    // Maximum of 30 pitch up or down
    if(pitch!=0){
      pitch += (pitch < 0) ? 0.5 : -0.5;
      pitch = Math.clamp(pitch, -30, 30);
    }

    var direction = new Quaternion;
    direction = direction.yaw(yaw).pitch(pitch);
    v = v.add(direction.multiply(velocity));
    
    // Move the avatar
    avatar.setPosition(v);
    direction = direction.roll(roll);
    avatar.setRotation(direction);

    // Set cammera position
    camera.setPosition(v.add(q.yaw(roll/2).multiply(new Vector(0, 5, -10))));
    camera.lookAt(v);
  }
  
  avatar.setPosition(new Vector(0, 20, 0));
  avatar.setScale(new Vector(3,3,3));
  
  Event.observe(this, "frameEnded", this.frameListener);
  
  return this;
}

function JumpingSheep(){
  print("Registered the jumping sheep controls");

  var avatar = world.createNode(),

    cameraDistance = 5,
    
    ySpeed = 0.0,
    gravity = 0.9 * (1 / fps),
    
    // Walk at x metres per second
    walkSpeed = 6 * (1 / fps),
    
    // Turn at x degrees per second
    turnSpeed = 90 * (1 / fps);
  
  this.frameListener = function(){
    world.stats.update();

    var v = avatar.getPosition(),
      q = avatar.getRotation();

    // All this crappiness is in here because we don't have a physics engine yet.
    v.y += ySpeed;
    ySpeed -= gravity;
    if(v.y < 0){
      v.y = 0;
    }
    
//    cameraDistance += oisinput.mouseY;
    
    if((v.y==0) && (oisinput.isKeyDown(Keycodes.KC_SPACE))){
      // Jump up at 12 metres per second
      ySpeed = 12 * (1 / fps);
    }

    if(oisinput.isKeyDown(Keycodes.KC_LEFT)){
      q = q.yaw(turnSpeed);
    }
    
    if(oisinput.isKeyDown(Keycodes.KC_RIGHT)){
      q = q.yaw(-turnSpeed);
    }
    
    if(oisinput.isKeyDown(Keycodes.KC_DOWN)){
      v = v.add(q.multiply(new Vector(0,0, -walkSpeed)));
    }
    
    if(oisinput.isKeyDown(Keycodes.KC_UP)){
      v = v.add(q.multiply(new Vector(0,0, walkSpeed)));
    }
    
    // Move the avatar
    avatar.setPosition(v);
    avatar.setRotation(q);

    // Set cammera position
    camera.setPosition(v.add(q.multiply(new Vector(0,0.5 * cameraDistance,-cameraDistance))));
    camera.lookAt(v);
  }
  
  Event.observe(this, "frameEnded", this.frameListener);
  
  return this;
}

function DefaultWalkControl(){
  print("Registered the default controls");

  var avatar = world.getNodeById("/Viewer/Avatar"),

    // Walk at x metres per second
    walkSpeed = 6 * (1 / 40),
    
    // Turn at x degrees per second
    turnSpeed = 90 * (1 / 40);
  
  this.frameListener = function(){
    var v = avatar.getPosition(),
      q = avatar.getRotation();

    if(oisinput.isKeyDown(Keycodes.KC_LEFT)){
      q.yaw(turnSpeed);
    }
    
    if(oisinput.isKeyDown(Keycodes.KC_RIGHT)){
      q.yaw(-turnSpeed);
    }
    
    if(oisinput.isKeyDown(Keycodes.KC_DOWN)){
      v = v.add(q.multiply(new Vector(0,0, -walkSpeed)));
    }
    
    if(oisinput.isKeyDown(Keycodes.KC_UP)){
      v = v.add(q.multiply(new Vector(0,0, walkSpeed)));
    }
    
    // Move the avatar
    avatar.setPosition(v);
    avatar.setRotation(q);

    // Set cammera position
    camera.setPosition(v.add(q.multiply(new Vector(0,3,-5))));
    camera.lookAt(v);
  }
  
  Event.observe(this, "frameEnded", this.frameListener);
  
  return this;
}

function MouselookControl(){
  print("Registered the mouselook controls");

  avatar = world.createNode();
  
  var pitch = -camera.getRotation().getPitch(),
    yaw = camera.getRotation().getYaw(),
    
    // Walk at x metres per second
    walkSpeed = 5 * (1 / 40),
    
    // Turn at x degrees per second
    turnSpeed = 90 * (1 / 40);
  
  this.frameListener = function(){
    //world.stats.update();
	
	var avatar_height = 1.8;
 
    var orientation = new Quaternion;
    orientation = orientation.yaw(yaw);
  
    var v = avatar.getPosition();

    if(oisinput.enabled){
      pitch -= oisinput.mouseY / 3;
      yaw -= oisinput.mouseX / 3;
    
      if(oisinput.leftMouseButton){
        v = v.add(orientation.multiply(new Vector(0,0, -walkSpeed)));
      }
    
  	  // FIXME craptacular jumping and crouching
      if(oisinput.isKeyDown(Keycodes.KC_C)){
		avatar_height = 0.8;
	  }
	
      if(oisinput.isKeyDown(Keycodes.KC_SPACE)){
		v.y = 10;
	  }

      if(oisinput.isKeyDown(Keycodes.KC_A)){
        v = v.add(orientation.yaw(90).multiply(new Vector(0,0, -walkSpeed)));
      }
    
      if(oisinput.isKeyDown(Keycodes.KC_D)){
        v = v.add(orientation.yaw(-90).multiply(new Vector(0,0, -walkSpeed)));
      }
    
      if(oisinput.isKeyDown(Keycodes.KC_S)){
        v = v.add(orientation.multiply(new Vector(0,0, walkSpeed)));
      }
    
      if(oisinput.isKeyDown(Keycodes.KC_W)){
        v = v.add(orientation.multiply(new Vector(0,0, -walkSpeed)));
      }
    }
    
	if(v.y>0){
		v.y -= 0.1;
	}
   // v.y = 0;
    
    // Move the avatar
    avatar.setPosition(v);
    avatar.setRotation(orientation);

    // Set cammera position
    camera.setPosition(v.add(new Vector(0,avatar_height,0))); //v.add(orientation.multiply(new Vector(0,3,-5))));
    camera.setRotation(orientation.pitch(pitch))
//    camera.lookAt(v);

    var q = new Quaternion;
    // Rotate the god sheeps head
    //world.god_sheep.entity.skeleton.getBone("head").setRotation(q.roll(-v.x * 10));

    var v = world.god_sheep.getPosition();
    v.z-=5 / 40;
//    world.god_sheep.setPosition(v);
  }
  
	avatar.setPosition(camera.getPosition());

	Event.observe(this, "frameEnded", this.frameListener);
  
//	world.sheep.entity.skeleton.getBone("head").setRotation($Q.roll(-v.x * 10));
  
  return this;
}

function Statsbox(){
  var xml = "<?xml version='1.0' ?>\
  <GUILayout>\
  <Window Type='Vanilla/StaticText' Name='Statsbox/stats'>\
    <Property Name='UnifiedPosition' Value='{{0,450},{0,550}}' />\
    <Property Name='UnifiedSize' Value='{{0,330},{0,40}}' />\
    <Property Name='HorzFormatting' Value='WordWrapLeftAligned' />\
    <Property Name='Text' Value='text...' />\
  </Window>\
  </GUILayout>";
  
  var win = desktop.createWindow(xml),
    avatar = world.getNodeById("/Viewer/Avatar");

  this.update = function(st){
    var v = avatar.getPosition(),
      locn;
      
    if ((Math.abs(v.z)<3) && (Math.abs(v.x)<3)){
      locn = "At the origin";
    }else{
      locn = Math.abs(Math.round(v.z)) + " metres " + (v.z<0 ? "north" : "south") + " and " + Math.abs(Math.round(v.x)) + " metres " + (v.x<0 ? "east" : "west") + " of the origin";
    }
    
    win.getWidgetById("Statsbox/stats").text = locn;
  }

  this.update();
  
  return this;
};

function Console(){
  var xml = "<?xml version='1.0' ?>\
  <GUILayout>\
  \
  <Window Type='Vanilla/FrameWindow' Name='JSConsole'>\
  <Property Name='UnifiedPosition' Value='{{0,10},{0,-100}}' />\
  <Property Name='UnifiedSize' Value='{{0,300},{0,430}}' />\
  <Property Name='DragMovingEnabled' Value='true' />\
  <Property Name='RollUpEnabled' Value='true' />\
  <Property Name='CloseButtonEnabled' Value='true' />\
  <Property Name='Text' Value='Console' />\
  \
  <Window Type='Vanilla/StaticText' Name='JSConsole/History'>\
  <Property Name='UnifiedPosition' Value='{{0,10},{0,30}}' />\
  <Property Name='UnifiedSize' Value='{{0,280},{0,350}}' />\
  <Property Name='VertFormatting' Value='BottomAligned' />\
  <Property Name='HorzFormatting' Value='WordWrapLeftAligned' />\
  <Property Name='Text' Value='text...' />\
  </Window>\
  \
  <Window Type='Vanilla/Editbox' Name='JSConsole/Commandline'>\
  <Property Name='UnifiedPosition' Value='{{0,10},{0,390}}' />\
  <Property Name='UnifiedSize' Value='{{0,210},{0,30}}' />\
  <Property Name='Text' Value='' />\
  </Window>\
  \
  <Window Type='Vanilla/Button' Name='JSConsole/Submit'>\
  <Property Name='UnifiedPosition' Value='{{0,230},{0,390}}' />\
  <Property Name='UnifiedSize' Value='{{0,60},{0,30}}' />\
  <Property Name='Text' Value='Execute' />\
  </Window>\
  \
  </Window>\
  \
  </GUILayout>";
  
  var lines = "Welcome to wonderland v0.01...\n\nPress escape to hide or show the console. When the console is hidden, press arrow keys to move around.\n\nClick on an object in the world to set the node variable to that object.\n\nPress apple-q to quit.\n\n".split("\n");
    
  var win = desktop.createWindow(xml);
  
  win.hide();

  var log = function(st){
    lines.push(st);
    win.getWidgetById("JSConsole/History").text = lines.join("\n");
  }

  var onsubmit = function(){
    var st = "";

    try{
      st = eval(win.getWidgetById("JSConsole/Commandline").text);
    }catch(e){
      st = e;
    }

    log(st);
  };

  log();

  win.getWidgetById("JSConsole/Submit")._connectEvent("click", onsubmit);
  win.getWidgetById("JSConsole/Commandline")._connectEvent("submit", onsubmit);
  
  this.log = log;

	var visible = false;
	
	var button = desktop.createWindow("<?xml version='1.0' ?>\n<GUILayout>\
	<Window Type='Vanilla/Button' Name='JSConsole/Toggle'>\
		<Property Name='UnifiedPosition' Value='{{0,10},{0,560}}' />\
		<Property Name='UnifiedSize' Value='{{0,60},{0,30}}' />\
		<Property Name='Text' Value='Console' />\
	</Window></GUILayout>");

	win.getWidgetById("JSConsole/Toggle")._connectEvent("click", function(){
		visible = !visible;
		visible ? win.show() : win.hide();
	});
  
  return this;
};

function Toolbox(){
	var win = desktop.createWindow("<?xml version='1.0' ?>\n<GUILayout>\
	<Window Type='Vanilla/Button' Name='Toolbox/Cube'>\
		<Property Name='UnifiedPosition' Value='{{0,80},{0,560}}' />\
		<Property Name='UnifiedSize' Value='{{0,90},{0,30}}' />\
		<Property Name='Text' Value='Drop cube' />\
	</Window></GUILayout>");

	win.getWidgetById("Toolbox/Cube")._connectEvent("click", function(){
		var cube = world.createNode();
		cube.entity.setMaterial("html/colors/red");
		
		// 5 meters ahead
		var v = avatar.getPosition().add(avatar.getRotation().multiply(new Vector(0,0,-5)));
		v = v.floor();
		v.y = 0.5;
		
		cube.setPosition(v);
	});
}

function Login(){
	var nickname, password;
	
	var dialog = desktop.createWindow("<?xml version='1.0' ?>\
		<GUILayout>\
		<Window Type='Vanilla/FrameWindow' Name='Login'>\
			<Property Name='UnifiedPosition' Value='{{0,250},{0,350}}' />\
			<Property Name='UnifiedSize' Value='{{0,300},{0,200}}' />\
			<Property Name='DragMovingEnabled' Value='true' />\
			<Property Name='RollUpEnabled' Value='false' />\
			<Property Name='CloseButtonEnabled' Value='true' />\
			<Property Name='Text' Value='Login to the wonderland project' />\
		<Window Type='Vanilla/StaticText' Name='Login/Nick/Label'>\
			<Property Name='UnifiedPosition' Value='{{0,10},{0,60}}' />\
			<Property Name='UnifiedSize' Value='{{0,100},{0,30}}' />\
			<Property Name='BackgroundEnabled' Value='False' />\
			<Property Name='FrameEnabled' Value='False' />\
			<Property Name='Text' Value='Username:' />\
		</Window>\
		<Window Type='Vanilla/Editbox' Name='Login/Nick'>\
			<Property Name='UnifiedPosition' Value='{{0,90},{0,60}}' />\
			<Property Name='UnifiedSize' Value='{{0,190},{0,30}}' />\
			<Property Name='Text' Value='' />\
		</Window>\
		<Window Type='Vanilla/StaticText' Name='Login/Password/Label'>\
			<Property Name='UnifiedPosition' Value='{{0,10},{0,100}}' />\
			<Property Name='UnifiedSize' Value='{{0,100},{0,30}}' />\
			<Property Name='BackgroundEnabled' Value='False' />\
			<Property Name='FrameEnabled' Value='False' />\
			<Property Name='Text' Value='Password:' />\
		</Window>\
		<Window Type='Vanilla/Editbox' Name='Login/Password'>\
			<Property Name='UnifiedPosition' Value='{{0,90},{0,100}}' />\
			<Property Name='UnifiedSize' Value='{{0,190},{0,30}}' />\
			<Property Name='Text' Value='' />\
			<Property Name='MaskText' Value='True' />\
		</Window>\
		<Window Type='Vanilla/Button' Name='Login/Submit'>\
			<Property Name='UnifiedPosition' Value='{{0,90},{0,140}}' />\
			<Property Name='UnifiedSize' Value='{{0,120},{0,30}}' />\
			<Property Name='Text' Value='Login' />\
		</Window>\
		</Window>\
		</GUILayout>");

	var con_dialog = desktop.createWindow("<?xml version='1.0' ?>\
		<GUILayout>\
		<Window Type='Vanilla/FrameWindow' Name='LoginStatus'>\
			<Property Name='UnifiedPosition' Value='{{0,250},{0,390}}' />\
			<Property Name='UnifiedSize' Value='{{0,300},{0,80}}' />\
			<Property Name='Text' Value='Connecting...' />\
		<Window Type='Vanilla/Button' Name='LoginStatus/Cancel'>\
			<Property Name='UnifiedPosition' Value='{{0,90},{0,40}}' />\
			<Property Name='UnifiedSize' Value='{{0,120},{0,30}}' />\
			<Property Name='Text' Value='Cancel' />\
		</Window>\
		</Window>\
		</GUILayout>");


	// Login pressed
	this.onsubmit = function(){
		nickname = dialog.getWidgetById("Login/Nick").text;
		password = dialog.getWidgetById("Login/Password").text;
		this.connect();
	}
  
	// Cancel login...
	this.oncancel = function(){
		con_dialog.hide();
		dialog.show();
		connection.disconnect();
	}
  
	this.connect = function(){
		dialog.hide();
		con_dialog.show();

		connection.nickname = nickname;
		connection.password = password;

		connection.connect();
		con_dialog.getWidgetById("LoginStatus").text = "Connecting to wonderlandproject.info...";
	}

//	this.onmessage = function(sender, message){
//		chat_window.log(sender.replace(/@.+/,'') + ": " + message);
//	}
  
	this.onconnected = function(){
		con_dialog.close();

		// Disable the gui - go into mouselook mode
		viewer = new MouselookControl;
		new Toolbox;
		
		oisinput.toggleGui();

		connection.send("god@wonderlandproject.info", "I just connected...");

	}

	this.onerror = function(err){
		con_dialog.getWidgetById("LoginStatus").text = "Error connecting";
	}
  
	// Hide the logging_in dialog
	con_dialog.hide();

	// GUI events
	dialog.getWidgetById("Login/Submit")._connectEvent("click", this.onsubmit.bind(this));
    con_dialog.getWidgetById("LoginStatus/Cancel")._connectEvent("click", this.oncancel.bind(this));

	// Connection events
	connection._connectEvent("connect", this.onconnected.bind(this));
	connection._connectEvent("error", this.onerror.bind(this));
	connection._connectEvent("disconnect", this.onerror.bind(this));
	//    connection._connectEvent("message", this.onmessage.bind(this));
}

function NoisyWorld(){
	// Create a bunch of random blocks

	for(i=0;i<10;i++){
	  var node = world.createNode(),
		x = Math.floor(Math.random() * 100 - 50),
		y = Math.random() * 5 + 1,
		z = Math.floor(Math.random() * 100 - 50);
		
	  var s = node.getScale();
	  s.y *= y;

	  node.setScale(s);
	  node.setPosition(new Vector(x,y / 2,z));
	  
	  // Event.observe(node, 'collision', function(self, sender){
	  //  connection.send(sender.jid, "OI! DONT CRASH INTO ME")
	  // });
	}


	// Create the massive sheep
	world.god_sheep = world.createNode();
	world.god_sheep.appendChild(world.createEntity("ram.mesh"));

	world.god_sheep.setScale(new Vector(5,5,5));
	world.god_sheep.setPosition(new Vector(0,0,20));
	Event.observe(node, 'click', function(sender){
	  connection.send(sender.jid, "ALL HAIL THE GODSHEEP");
	});

	//Make it face us
	world.god_sheep.setRotation($Q.yaw(180));

	// Enable the animation
	//world.god_sheep.entity.animations[0].enable();

	var avatar = world.getNodeById("/Viewer/Avatar");
//	avatar.entity.animations[0].enable();

	// foreach(avatar.entity.skeleton.bones, function(){
	//   print(this.name);
	// });

	// foreach(avatar.entity.animations, function(){
	//   print(this.name);
	// });
}

CameraSpin = function(){
	var r = 0;
	
	this.frameListener = function(){
		r+=0.3;

		var q = new Quaternion,
			v = new Vector(0,10,15);
			
		camera.setPosition(q.yaw(r).multiply(v));
		camera.lookAt(new Vector(0,-2,0));
	}

	var sheep = world.createNode();
		sheep.appendChild(world.createEntity("ram.mesh"));
		sheep.setScale(new Vector(1,1,1));
		sheep.setPosition(new Vector(0.8,0,-2.5));
		sheep.setRotation($Q.yaw(90));
		
	world.sheep = sheep;

	var node = world.createNode(),
		entity = world.createEntity("wlogo.mesh");
	entity.setMaterial('html/colors/silver');
	node.appendChild(entity);
	node.setScale(new Vector(10,10,10));
	node.setPosition(new Vector(0,0,4));
	node.setRotation($Q.yaw(90));

		console.log(entity.getSize().inspect());
		
	Event.observe(this, "frameEnded", this.frameListener);
}

var console = new Console;

viewer = new CameraSpin;
new Login;

// world.stats = new Statsbox;
// viewer = new MouselookControl;

"ok";